package com.zc.config;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

/**
 * redis配置
 *
 * @author inspur
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {

    private static final Long TTL_DAY = 60 * 60 * 24L;
    private static final Long TTL_WEEK = 60 * 60 * 24 * 7L;
    private static final Long TTL_MONTH = 60 * 60 * 24 * 30L;


    private static final RedisSerializer<String> strSerializer = new StringRedisSerializer();
    @SuppressWarnings(value = {"rawtypes"})
    private static final FastJson2JsonRedisSerializer fastJson2JsonRedisSerializer = new FastJson2JsonRedisSerializer<>(Object.class);
    @SuppressWarnings(value = {"rawtypes"})
    private static final FastJson2JsonRedisHashValueSerializer fastJson2JsonRedisHashValueSerializer = new FastJson2JsonRedisHashValueSerializer<>(Object.class);


    @Bean
    @SuppressWarnings(value = {"unchecked", "rawtypes"})
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(strSerializer);
        template.setValueSerializer(fastJson2JsonRedisSerializer);

        // Hash的key也采用StringRedisSerializer的序列化方式
        template.setHashKeySerializer(strSerializer);
        template.setHashValueSerializer(fastJson2JsonRedisHashValueSerializer);

        template.afterPropertiesSet();
        return template;
    }

    @Bean
    @SuppressWarnings(value = {"unchecked", "rawtypes"})
    public RedisTemplate<Object, Object> myRedisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(RedisSerializer.string());
        template.setValueSerializer(RedisSerializer.string());

        // Hash的key也采用StringRedisSerializer的序列化方式
        template.setHashKeySerializer(RedisSerializer.string());
        template.setHashValueSerializer(RedisSerializer.json());

        template.afterPropertiesSet();
        return template;
    }

    @Bean
    @SuppressWarnings(value = {"unchecked", "rawtypes"})
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        return RedisCacheManager.RedisCacheManagerBuilder
                // Redis 连接工厂
                .fromConnectionFactory(connectionFactory)
                .cacheDefaults(getCacheConfigurationWithTtl(TTL_WEEK)) // 默认缓存7天
                // 配置同步修改或删除 put/evict
                .transactionAware()
                .build();
    }

    @SuppressWarnings(value = {"unchecked", "rawtypes"})
    private RedisCacheConfiguration getCacheConfigurationWithTtl(long seconds) {
        return RedisCacheConfiguration
                .defaultCacheConfig()
                // 设置key为String
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(strSerializer))
                // 设置value 为自动转Json的Object
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJson2JsonRedisSerializer))
                // 不缓存null
                .disableCachingNullValues()
                // 变双冒号为单冒号
                .computePrefixWith(keyName -> keyName + ":")
                // 缓存数据超时时间
                .entryTtl(Duration.ofSeconds(seconds));

    }
}
